<?php
define('FXO', 0xFFFF);
define('FXO_KEY', 0x10000);
define('FXO_KEY_SJ', 0x20);
define('aes_bm','aes-256-cbc');
define('sj_chart','abcdefghijklmnopqrstuvwxyz0123456789');
define('sj_chart2','0123456789abcdefghijklmnopqrstuvwxyz');
/**-------------------------------------------------------------------------------------------
 * 熙鹤数据加/解密
 * @version 1.0
 * @author 熙鹤
 * @date 2024-10-5
 * @copyright YH 2024-2025 All Rights Reserved.
 * @website https://yhknow.top
*/
class yh_enc {
    private function texttohex($string) {
        $hex = '';
        for ($i = 0; $i < strlen($string); $i++) {
            $hex .= dechex(ord($string[$i]));
        }
        return '0x' . $hex;
    }
    private function case_enc($ciphertext, $key) {
        $plaintext = '';
        $key = $key % 26; 
        for ($i = 0; $i < strlen($ciphertext); $i++) {
            $char = $ciphertext[$i];
            if (ctype_alpha($char)) {
                $offset = ctype_upper($char) ? 65 : 97; 
                $char = chr((ord($char) - $offset - $key + 26) % 26 + $offset); 
            }
            $plaintext .= $char;
        }
        return $plaintext;
    }
    private function case_dec($text, $key) {
        $result = "";
        $key = $key % 26;
        for ($i = 0; $i < strlen($text); $i++) {
            $char = $text[$i];
            if (ctype_alpha($char)) { 
                $offset = ctype_upper($char) ? 65 : 97; 
                $char = chr(($offset + (ord($char) - $offset + $key) % 26));
            }
            $result .= $char;
        }
        return $result;
    }
    private function bmone_tohexstring($s) {
        if (strlen($s) == 0) {
            return '';
        }
        $array = array();
        for ($i = 0; $i < strlen($s); $i++) {
            $array[] = dechex(ord($s[$i]));
        }
        $nowpspl = implode(',', $array);
        return $nowpspl;
    }
    private function turntowbarray($inputwb){
        $pairs = explode(';', $inputwb);
        $mapping = [];
        foreach ($pairs as $pair) {
            list($key, $value) = explode(',', $pair);
            $mapping[$key] = $value;
        }
        return $mapping;
    }
    private function gentusjjzzdzsc($length = 5, $characters = sj_chart2) {
        $charactersLength = strlen($characters);
        $randomString = '';
        for ($i = 0; $i < $length; $i++) {
            $randomString .= $characters[rand(0, $charactersLength - 1)];
        }
        return $randomString;
    }
    private function starttosjscmgwb($count = 8) {
        $keyValuePairs = [];
        $usedKeys = [];
        $usedValues = [];
        for ($i = 0; $i < $count; $i++) {
            do {
                $key = chr(rand(97, 122));
            } while (isset($usedKeys[$key]));
            $usedKeys[$key] = true;
    
            do {
                $value = $this->gentusjjzzdzsc();
            } while (isset($usedValues[$value]));
            $usedValues[$value] = true;
    
            $keyValuePairs[] = $key . ',' . $value;
        }
        return implode(';', $keyValuePairs);
    }
    private function aes_encrypt($data,$keysy){
        $key = $keysy;
        $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length(aes_bm));
        $encrypted = openssl_encrypt($data, aes_bm, $key, 0, $iv);
        $encrypted_data = base64_encode($iv . $encrypted);
        return $encrypted_data;
    }
    private function aes_decrypt($data,$keysy){
        $key = $keysy;
        $data = base64_decode($data);
        $iv = substr($data, 0, openssl_cipher_iv_length(aes_bm));
        $encryptedData = substr($data, openssl_cipher_iv_length(aes_bm));
        return openssl_decrypt($encryptedData, aes_bm, $key, 0, $iv);
    }
    private function bmone_tojsstring($s) {
        if (strlen($s) == 0) {
            return '';
        }
        $reText = '';
        $fmtarray = explode(',', $s);
        foreach ($fmtarray as $val) {
            $reText .= chr(hexdec($val));
        }
        return $reText;
    }

    private function changeletttonum($str, $mappingg) {
        $mapping = $mappingg;
        return implode('', array_map(function($letter) use ($mapping) {
            return isset($mapping[$letter]) ? $mapping[$letter] : $letter;
        }, str_split($str)));
    }

    private function encrypt_simple($content, $shift) {
        $encryptedContent = '';
        for ($i = 0; $i < strlen($content); $i++) {
            $charCode = ord($content[$i]) + $shift;
            if ($charCode > FXO) {
                $charCode -= FXO_KEY;
            }
            $encryptedContent .= chr($charCode);
        }
        return $encryptedContent;
    }

    private function decrypt_simple($encryptedContent, $shift) {
        $decryptedContent = '';
        for ($i = 0; $i < strlen($encryptedContent); $i++) {
            $charCode = ord($encryptedContent[$i]) - $shift;
            if ($charCode < FXO_KEY_SJ) {
                $charCode += FXO_KEY;
            }
            $decryptedContent .= chr($charCode);
        }
        return $decryptedContent;
    }

    private function encrypt_othtaes($content, $key) {
        $key = (string)$key;
        $encryptedContent = '';
        for ($i = 0; $i < strlen($content); $i++) {
            $charCode = ord($content[$i]) ^ ord($key[$i % strlen($key)]);
            $encryptedContent .= chr($charCode);
        }
        return $encryptedContent;
    }

    private function decrypt_othtaes($encryptedContent, $key) {
        $decryptedContent = '';
        for ($i = 0; $i < strlen($encryptedContent); $i++) {
            $charCode = ord($encryptedContent[$i]) ^ ord($key[$i % strlen($key)]);
            $decryptedContent .= chr($charCode);
        }
        return $decryptedContent;
    }

    private function generateRandomString($length = 7) {
        $characters = sj_chart;
        $charactersLength = strlen($characters);
        $randomString = '';
        for ($i = 0; $i < $length; $i++) {
            $randomChar = $characters[rand(0, $charactersLength - 1)];
            $randomString .= $randomChar;
        }
        return $randomString;
    }
    /** 
     * @param string $content 待加密的内容
     * @param string $passkey 加密密钥(4-9位)
     */
    public function yh_encrypt($content,$passkey) {
        if(strlen($passkey) <4 || strlen($passkey) >= 10){
            throw new Exception('密钥长度错误,应为4-9位');
        }
        $hexkeyaf = $this->texttohex($passkey);
        $startsjzfwb = $this->starttosjscmgwb();
        $shift = 8;
        $datetimenow = round(microtime(true) * 1000);
        $randomword2 = $this->generateRandomString();
        $randomword = $this->bmone_tohexstring($randomword2);
        $cfcontentin = "/*--$randomword--$datetimenow--*/";
        $startsjzfwb2 = $this->encrypt_othtaes($startsjzfwb, substr($passkey,4).substr($datetimenow,3).substr($randomword2,2));
        $mappingsjs = $this->turntowbarray($startsjzfwb);
        $simpleEncryptedContent = $this->encrypt_simple($content, $shift);
        $key = substr((string)$datetimenow, 4) . $this->changeletttonum($randomword2,$mappingsjs) . $randomword;
        $aesEncryptedContent = $this->encrypt_othtaes($simpleEncryptedContent, $key);
        $aesEncryptedContent2 = $this->aes_encrypt($aesEncryptedContent, substr((string)$datetimenow, 5).$randomword2.$passkey);
        $snajint2 =  $cfcontentin . "\n" . $startsjzfwb2."\n".$this->bmone_tohexstring($aesEncryptedContent2);
        $snajint = chunk_split(base64_encode($snajint2),2000,"\r\n");
        $lastbehexcase = 'YHJM-For absolutely confidential data'."\n". $this->case_dec($snajint,$hexkeyaf);
        return $lastbehexcase;
    }
    /** 
     * @param string $encryptedContent 待解密的内容
     * @param string $passkey 解密密钥(4-9位)
     */
    public function yh_decrypt($encryptedContent,$passkey) {
        $hexkeyaf = $this->texttohex($passkey);
        $pattern = "/\n{2,}/";
        $encryptedContent = str_replace($pattern, '\n', $encryptedContent);
        $liness = explode("\n", $encryptedContent);
        $filteredLines = array_filter($liness, function($line) {
            return trim($line) !== '';
        });
        $filteredText =  implode("\n",array_slice($filteredLines, 1));
        $filteredText2 = $this->case_enc($filteredText,$hexkeyaf);
        $encryptedContent = base64_decode($filteredText2);
        $lines = explode("\n", $encryptedContent);
        $cfcontentin = $lines[0];
        $parts = explode('--', $cfcontentin);
        $randomiword2 = $parts[1];
        $nowtimeword = $parts[2];
        $randomword = $this->bmone_tojsstring($randomiword2);
        $startsjzfwbjm = $this->decrypt_othtaes($lines[1], substr($passkey,4).substr($nowtimeword,3).substr($randomword,2));
        $mappingsjss2 = $this->turntowbarray($startsjzfwbjm);
        $key = substr($nowtimeword, 4) . $this->changeletttonum($randomword,$mappingsjss2) . $randomiword2;
        $aesEncryptedContent = $this->bmone_tojsstring(substr($encryptedContent, strlen($cfcontentin) + 1));
        $aesEncryptedContent2 = $this->aes_decrypt($aesEncryptedContent, substr($nowtimeword, 5).$randomword.$passkey);
        $simpleEncryptedContent = $this->decrypt_othtaes($aesEncryptedContent2, $key);
        $decryptedContent = $this->decrypt_simple($simpleEncryptedContent, 8);
        return $decryptedContent;
    }
}
?>